import pygame  # 2D游戏库
import sys  # 系统相关的库
from 游戏设置 import 类_游戏设置
from 飞船 import 类_飞船
from 子弹 import 类_飞船子弹
from 外星人 import 类_外星人


class 类_管理游戏资源和行为:
    """管理游戏资源和行为的类"""

    def __init__(self):
        """初始化游戏并创建游戏资源"""
        pygame.init()  # 游戏库的初始化
        self.设置 = 类_游戏设置()  # 创建一个实例,以后加载设置都是实例来

        self.游戏窗口 = pygame.display.set_mode((self.设置.窗口高度, self.设置.窗口宽度))  # 游戏窗口分辨率 如果要全屏这行注释掉,启用下面3行
        # self.游戏窗口 = pygame.display.set_mode((0,0), pygame.FULLSCREEN)  # 游戏窗口可以全屏
        # self.设置.窗口宽度 = self.游戏窗口.get_rect().width  # 如果窗口全屏,窗口宽度的值就是全屏时的值.而不是我们设置的值
        # self.设置.窗口高度 = self.游戏窗口.get_rect().height  # 窗口高度也是一样的
        pygame.display.set_caption("外星人大战")  # 窗口的标题

        self.飞船 = 类_飞船(self)  # 创建飞船类的实例 (把自身类,作为参数传给另一个类)
        self.外星人 = 类_外星人(self)  # 创建外星人类实例

        self.子弹编组 = pygame.sprite.Group()  # 实例用于存储所有发射的子弹
        self.外星人编组 = pygame.sprite.Group()  # 实例用于存储处理所有的外星人

        self._外星人舰队()

    def 开始游戏(self):  # 控制游戏的函数
        """开始游戏的主循环"""
        while True:
            self._检查事件()
            self.飞船.更新飞船移动()
            self._更新_子弹编组()
            self._更新屏幕()

    # 下面私有方法,单独建立出来.方便以后添加新代码,与上面的主控分开来
    def _检查事件(self):
        """响应按键和鼠标事件"""
        # 监视键盘和鼠标事件
        for 操作 in pygame.event.get():  # 这个函数会返回,鼠标键盘的事件(操作).每次遍历
            if 操作.type == pygame.QUIT:  # 侦测关闭操作(比如鼠标点击关闭按钮)
                sys.exit()  # 退出窗口(也就是关闭窗口)

            # 这里我们要实现按住方向键(飞船)一直移动,松开停止移动
            elif 操作.type == pygame.KEYDOWN:  # 检查是否按键
                self._检查KEYDOWN事件(操作)

            elif 操作.type == pygame.KEYUP:  # 检查 松开按键
                self._检查KEYUP事件(操作)

    def _检查KEYDOWN事件(self, 操作):
        """响应按键 相应的按键控制飞船移动"""
        if 操作.key == pygame.K_RIGHT:  # 检查按键是否 右方向键
            self.飞船.向右移动 = True
        elif 操作.key == pygame.K_LEFT:  # 检查按键是否 左方向键
            self.飞船.向左移动 = True
        elif 操作.key == pygame.K_UP:  # 检查按键是否 上方向键
            self.飞船.向上移动 = True
        elif 操作.key == pygame.K_DOWN:  # 检查按键是否 下方向键
            self.飞船.向下移动 = True
        elif 操作.key == pygame.K_ESCAPE:  # 按下Esc键,也可以关闭游戏屏幕(教程是q键盘 知道就好)
            sys.exit()
        elif 操作.key == pygame.K_SPACE:  # 检查 空格键,是就创建一个子弹的矩形
            self._子弹()

    def _检查KEYUP事件(self, 操作):
        """响应松开按键 松开按键停止移动飞船"""
        if 操作.key == pygame.K_RIGHT:  # 如果检查到松开按键,赋值 False ,停止移动飞船(矩形)
            self.飞船.向右移动 = False
        elif 操作.key == pygame.K_LEFT:
            self.飞船.向左移动 = False
        elif 操作.key == pygame.K_UP:
            self.飞船.向上移动 = False
        elif 操作.key == pygame.K_DOWN:
            self.飞船.向下移动 = False

    def _更新屏幕(self):
        """更新屏幕上的图像,并切换到新屏幕"""
        # 每次循环都重绘屏幕
        self.游戏窗口.fill(self.设置.窗口背景颜色)  # 就是每次都刷新屏幕,可以显示我们设置的背景颜色(这个必须第一个执行位置不能改)

        self.飞船.战斗飞船()  # 调用 类_飞船,里的方法

        for 子弹 in self.子弹编组.sprites():  # 这个 sprites 返回的是个列表 (把飞船显示在屏幕上)
            子弹.绘制子弹()
            子弹.子弹坐标更新()  # 通过不断循环移动子弹(矩形)坐标,实现视觉上的向上移动(教程里没有这行代码,运行正常.但我这里子弹不能向上移动)

        # self.外星人编组.draw(self.游戏窗口) (教程的)
        self.外星人.外星人_绘制()  # 把外星人显示在屏幕上(教程没有)

        # 让最近绘制的屏幕看见
        pygame.display.flip()  # 游戏的每一次操作叫绘制,需要刷新屏幕才能看到

    def _子弹(self):
        """创建一个子弹,并将其加入编组 "子弹编组" 中"""
        if len(self.子弹编组) < self.设置.子弹数量限制:  # 限制子弹发射数量(子弹编组 返回是个列表,检查列表元素数量小于设置的限制)
            新子弹 = 类_飞船子弹(self)  # 创建实例
            self.子弹编组.add(新子弹)

    def _更新_子弹编组(self):
        """更新子弹的位置,并删除消失出屏幕的子弹"""
        # 更新子弹位置
        self.子弹编组.update()

        # 删除消失的子弹  子弹发射不会真正消失,而是离开屏幕而已.这样会占用性能.我们要真正删除离开屏幕的子弹
        for 子弹1 in self.子弹编组.copy():  # copy 是子弹编组.sprites(),列表的副本
            if 子弹1.矩形.bottom <= 0:  # 子弹矩形底部的坐标小于0时
                self.子弹编组.remove(子弹1)  # 删除这个子弹
            # print(len(self.子弹编组))  # 验证列表个数,证明子弹矩形 真删除了(验证完删除这行,会拖慢游戏运行)

    def _外星人舰队(self):
        """创建一群外星人"""
        # 创建一个外星人
        新外星人 = 类_外星人(self)  # 创建实例
        self.外星人编组.add(新外星人)


if __name__ == '__main__':
    # 创建游戏实例并且运行游戏
    游戏 = 类_管理游戏资源和行为()
    游戏.开始游戏()
